package com.bushro.rpc.client;

import com.bushro.rpc.client.proxy.RpcAsyncProxy;
import com.bushro.rpc.client.proxy.RpcProxyImpl;

import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * $RpcClient
 *
 * @author bushro
 */
public class RpcClient {

    private String serverAddress;

    private long timeout;

    private final Map<Class<?>, Object> syncProxyIntanceMap = new ConcurrentHashMap<Class<?>, Object>();

    private final Map<Class<?>, Object> asyncProxyIntanceMap = new ConcurrentHashMap<Class<?>, Object>();


    public void initClient(String serverAddress, long timeout) {
        this.serverAddress = serverAddress;
        this.timeout = timeout;
        connect();
    }

    private void connect() {
        RpcConnectManager.getInstance().connect(serverAddress);
    }

    public void stop() {
        RpcConnectManager.getInstance().stop();
    }

    /**
     * $invokeSync 同步调用方法
     *
     * @param <T>
     * @param interfaceClass
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T invokeSync(Class<T> interfaceClass) {
        if (syncProxyIntanceMap.containsKey(interfaceClass)) {
            return (T) syncProxyIntanceMap.get(interfaceClass);
        } else {
            /**
             * ClassLoader loader ：类加载器
             * Class<?>[] interfaces :接口数组
             * InvocationHandler ：实现InvocationHandler接口的代理类
             */
            Object proxy = Proxy.newProxyInstance(interfaceClass.getClassLoader(),
                    new Class<?>[]{interfaceClass},
                    new RpcProxyImpl<>(interfaceClass, timeout));
            syncProxyIntanceMap.put(interfaceClass, proxy);
            return (T) proxy;
        }
    }

    /**
     * $invokeAsync 异步调用方式的方法
     *
     * @param <T>
     * @param interfaceClass
     * @return
     */
    public <T> RpcAsyncProxy invokeAsync(Class<T> interfaceClass) {
        if (asyncProxyIntanceMap.containsKey(interfaceClass)) {
            return (RpcAsyncProxy) asyncProxyIntanceMap.get(interfaceClass);
        } else {
            RpcProxyImpl<T> asyncProxyInstance = new RpcProxyImpl<>(interfaceClass, timeout);
            asyncProxyIntanceMap.put(interfaceClass, asyncProxyInstance);
            return asyncProxyInstance;
        }
    }

}
